package io.task.cc.network.maintain;

import io.task.cc.network.ChannelContext;
import io.task.cc.network.utils.lock.LockUtils;
import io.task.cc.network.utils.lock.LockedMap;
import io.task.cc.network.utils.lock.LockedSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.HashSet;

/**
 * 一对多  (ip <--> ChannelContext)<br>
 * 一个ip有哪些客户端，该维护只在Server侧有<br>
 */
public class Ips {

    private static final Logger log = LoggerFactory.getLogger(Ips.class);

    /**
     * 一个IP有哪些客户端
     * key: ip
     * value: SetWithLock<ChannelContext>
     */
    private final LockedMap<String, LockedSet<ChannelContext>> map = new LockedMap<>(new HashMap<String, LockedSet<ChannelContext>>());
    private final String rwKey = "_ips_";

    /**
     * 和ip绑定
     */
    public void bind(ChannelContext channelContext) {
        if (channelContext == null) {
            return;
        }


        try {
            String ip = channelContext.getClientNode().getIp();
            if (ChannelContext.UNKNOWN_ADDRESS_IP.equals(ip)) {
                return;
            }


            LockedSet<ChannelContext> set = map.get(ip);
            if (set == null) {
                LockUtils.runWriteOrWaitRead(rwKey + ip, this, () -> {
//					@Override
//					public void read() {
//					}

//					@Override
//					public void write() {
//						SetWithLock<ChannelContext> channelSet = ipmap.get(ip);
                    if (map.get(ip) == null) {
//							channelSet = new SetWithLock<>(new HashSet<ChannelContext>());
                        map.put(ip, new LockedSet<>(new HashSet<ChannelContext>()));
                    }
//					}
                });
                set = map.get(ip);
            }
            set.add(channelContext);
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }

    /**
     * 一个ip有哪些客户端，有可能返回null
     */
    public LockedSet<ChannelContext> clients(String ip) {


        return map.get(ip);
    }

    /**
     * 与指定ip解除绑定
     */
    public void unbind(ChannelContext channelContext) {
        if (channelContext == null) {
            return;
        }


        try {
            String ip = channelContext.getClientNode().getIp();

            if (ChannelContext.UNKNOWN_ADDRESS_IP.equals(ip)) {
                return;
            }

            LockedSet<ChannelContext> set = map.get(ip);
            if (set != null) {
                set.remove(channelContext);
                if (set.size() == 0) {
                    map.remove(ip);
                }
            } else {
                log.info("{}, ip【{}】 找不到对应的SetWithLock", channelContext.config.getName(), ip);
            }
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }
}
